/**
 *    Copyright (c) [2022] [中和农信]
 *    rabbit-mq-plus is licensed under Mulan PSL v2.
 *    You can use this software according to the terms and conditions of the Mulan PSL v2.
 *    You may obtain a copy of Mulan PSL v2 at:
 *             http://license.coscl.org.cn/MulanPSL2
 *    THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 *    See the Mulan PSL v2 for more details.
 *
 */
package com.cfpamf.athean.rabbit.mq.plus.producer.core.impl;

import java.util.Objects;

import javax.annotation.Resource;

import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;

import com.cfpamf.athean.rabbit.mq.plus.common.exception.RabbitMqPlusException;
import com.cfpamf.athean.rabbit.mq.plus.domain.builder.RabbitMqPlusEventTaskBuilder;
import com.cfpamf.athean.rabbit.mq.plus.domain.dto.RabbitMqPlusEventTaskDTO;
import com.cfpamf.athean.rabbit.mq.plus.domain.dto.RabbitMqPlusMessageDTO;
import com.cfpamf.athean.rabbit.mq.plus.producer.core.RabbitMqPlusProducer;
import com.cfpamf.athean.rabbit.mq.plus.producer.core.event.RabbitMqPlusProducerMessageSendEvent;
import com.cfpamf.athean.rabbit.mq.plus.service.RabbitMqPlusEventTaskService;
import com.cfpamf.athean.rabbit.mq.plus.service.RabbitMqPlusProducerService;

import lombok.NonNull;
import lombok.extern.slf4j.Slf4j;

/**
 * 类DefaultRabbitMqProducer.java的实现描述：
 *
 * @author Andy（陈洪桥）2022年11月25 22:08
 */
@Slf4j
@Component("rabbitMqPlusProducer")
public class DefaultRabbitMqPlusProducer implements RabbitMqPlusProducer {

    @Resource
    private RabbitMqPlusEventTaskService rabbitMqPlusEventTaskService;

    @Resource
    private RabbitTemplate rabbitTemplate;

    @Resource
    private RabbitMqPlusProducerService rabbitMqPlusProducerService;

    @Resource
    private ApplicationContext applicationContext;

    /**
     * 发送事件消息
     * 
     * <pre>
     * 调用方，需要在事物内最后一行，执行此方法
     * </pre>
     * 
     * @param rabbitMqMessageDTO
     * @throws RabbitMqPlusException
     */
    @Override
    public void sendTransactionalMessage(@NonNull final RabbitMqPlusMessageDTO rabbitMqPlusMessageDTO)
        throws RabbitMqPlusException {
        try {
            if (log.isDebugEnabled()) {
                log.debug("[rabbitMqPlus]生产者消息发送，开始。{} {} {}", rabbitMqPlusMessageDTO.getExchange(),
                    rabbitMqPlusMessageDTO.getEventNo(), rabbitMqPlusMessageDTO.getEventTypeCode());
            }
            RabbitMqPlusEventTaskDTO task = rabbitMqPlusEventTaskService.queryByEventNoAndEventCode(
                rabbitMqPlusMessageDTO.getEventNo(), rabbitMqPlusMessageDTO.getEventTypeCode());
            if (Objects.nonNull(task)) {
                log.info("[rabbitMqPlus]生产者消息记录DB，已存在拒绝重复记录。exchange {} eventNo {} eventTypeCode {}",
                    rabbitMqPlusMessageDTO.getExchange(), rabbitMqPlusMessageDTO.getEventNo(),
                    rabbitMqPlusMessageDTO.getEventTypeCode());
                return;
            }
            // 发送事件消息意向记录，写DB
            RabbitMqPlusEventTaskDTO rabbitMqPlusEventTaskDTO =
                RabbitMqPlusEventTaskBuilder.buildRabbitMqPlusEventTaskDTO(rabbitMqPlusMessageDTO);
            rabbitMqPlusEventTaskService.save(rabbitMqPlusEventTaskDTO);
            // 异步处理其他流程，通过事物提交事件，驱动消息主动发送
            applicationContext.publishEvent(new RabbitMqPlusProducerMessageSendEvent(this, rabbitMqPlusMessageDTO));
            log.info("[rabbitMqPlus]publishEvent投递完成:{} {} {}", rabbitMqPlusMessageDTO.getExchange(),
                rabbitMqPlusMessageDTO.getEventNo(), rabbitMqPlusMessageDTO.getEventTypeCode());
        } catch (Exception e) {
            if (log.isDebugEnabled()) {
                log.debug("[rabbitMqPlus]生产者消息发送，异常。{} {} {} {}", rabbitMqPlusMessageDTO.getExchange(),
                    rabbitMqPlusMessageDTO.getEventNo(), rabbitMqPlusMessageDTO.getEventTypeCode(), e.getMessage());
            }
            throw new RabbitMqPlusException("[rabbitMqPlus]生产者消息发送，异常", e);
        }
    }

}
